home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OWLSRC.PAK / MENU.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  12KB  |  496 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1991, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.13  $
  6. //
  7. // Implementation of classes TMenu and TXMenu, Window Menu encapsulation class
  8. // and its associated exception
  9. //----------------------------------------------------------------------------
  10. #include <owl/pch.h>
  11. #if !defined(OWL_MENU_H)
  12. # include <owl/menu.h>
  13. #endif
  14. #if !defined(OWL_MODULE_H)
  15. # include <owl/module.h>
  16. #endif
  17.  
  18. OWL_DIAGINFO;
  19. DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlMenu, 1, 0); // diag. group for menus
  20. DIAG_DECLARE_GROUP(OwlWin);                     // diag. group for windows
  21.  
  22. #if defined(BI_PLAT_WIN32)
  23. //
  24. //
  25. //
  26. TMenuItemInfo::TMenuItemInfo(uint msk)
  27. {
  28.   memset(LPMENUITEMINFO(this), 0, sizeof(MENUITEMINFO));
  29.   cbSize = sizeof(MENUITEMINFO);
  30.   fMask = msk;
  31. }
  32.  
  33. //
  34. //
  35. //
  36. TMenuItemInfo::TMenuItemInfo(TMenu& menu, uint posOrId, bool isPos, uint msk)
  37. {
  38.   PRECONDITION(menu.GetHandle());
  39.   memset(LPMENUITEMINFO(this), 0, sizeof(MENUITEMINFO));
  40.   cbSize = sizeof(MENUITEMINFO);
  41.   fMask = msk;
  42.   menu.GetMenuItemInfo(posOrId, isPos ? TRUE : FALSE, *this);
  43. }
  44.  
  45. //
  46. //
  47. //
  48. TMenuItemInfo::TMenuItemInfo(TMenu& menu, uint posOrId, bool isPos, 
  49.                              void* buffer, uint size, uint msk)
  50. {
  51.   PRECONDITION(menu.GetHandle());
  52.   memset(LPMENUITEMINFO(this), 0, sizeof(MENUITEMINFO));
  53.   cbSize = sizeof(MENUITEMINFO);
  54.   fMask = msk;
  55.   dwTypeData = LPTSTR(buffer);
  56.   cch = size;
  57.   menu.GetMenuItemInfo(posOrId, isPos ? TRUE : FALSE, *this);
  58. }
  59.  
  60. #endif
  61.  
  62. //
  63. // Construct a menu using CreateMenu()
  64. //
  65. TMenu::TMenu(TAutoDelete autoDelete)
  66. :
  67.   Handle(::CreateMenu()),
  68.   ShouldDelete(autoDelete)
  69. {
  70.   WARNX(OwlMenu, !Handle, 0, "Cannot Create Menu");
  71.   CheckValid();
  72. }
  73.  
  74. //
  75. // Construct a menu as a deep copy of an exisiting menu
  76. //
  77. TMenu::TMenu(const TMenu& original, TAutoDelete autoDelete)
  78. :
  79.   Handle(::CreateMenu()),
  80.   ShouldDelete(autoDelete)
  81. {
  82.   WARNX(OwlMenu, !Handle, 0, "Cannot Create Menu for Copy");
  83.   CheckValid();
  84.   DeepCopy(*this, original);
  85. }
  86.  
  87. //
  88. // Construct a menu as an alias for an existing handle
  89. //
  90. TMenu::TMenu(HMENU handle, TAutoDelete autoDelete)
  91. :
  92.   Handle(handle),
  93.   ShouldDelete(autoDelete)
  94. {
  95. }
  96.  
  97. //
  98. // Construct a menu alias for a given window's menu
  99. //
  100. TMenu::TMenu(HWND hWnd, TAutoDelete autoDelete)
  101. :
  102.   Handle(::GetMenu(hWnd)),
  103.   ShouldDelete(autoDelete)
  104. {
  105.   PRECONDITION(hWnd);
  106.   WARNX(OwlMenu, !Handle, 0, "Cannot Get Menu from " << hex << (uint)hWnd);
  107.   CheckValid();
  108. }
  109.  
  110. //
  111. // Construct a menu from a menu template struct
  112. //
  113. TMenu::TMenu(const void far* menuTemplate)
  114. {
  115.   PRECONDITION(menuTemplate);
  116.   Handle = ::LoadMenuIndirect(menuTemplate);
  117.   WARNX(OwlMenu, !Handle, 0, "Cannot Load Menu Indirect " << hex <<\
  118.         uint32(menuTemplate));
  119.   CheckValid();
  120.   ShouldDelete = true;
  121. }
  122.  
  123. //
  124. // Construct a menu by loading it from resource
  125. //
  126. TMenu::TMenu(HINSTANCE resInstance, TResId resId)
  127. {
  128.   PRECONDITION(resInstance && resId);
  129.   Handle = ::LoadMenu(resInstance, resId);
  130.   WARNX(OwlMenu, !Handle, 0, "Cannot Load Menu " << hex << (uint)resInstance <<\
  131.                             " " << resId);
  132.   CheckValid();
  133.   ShouldDelete = true;
  134. }
  135.  
  136. //
  137. // Copy an existing menu onto this menu, using DeepCopy
  138. //
  139. TMenu&
  140. TMenu::operator =(const TMenu& original)
  141. {
  142.   // Delete all items and submenus
  143.   // Look at possible alternatives for !ShouldDelete menus? Maybe use Remove
  144.   // then?
  145.   //
  146.   while (GetMenuItemCount())
  147.     DeleteMenu(0, MF_BYPOSITION);
  148.   DeepCopy(*this, original);
  149.   return *this;
  150. }
  151.  
  152. //
  153. // Destruct the menu by destroying the handle if appropriate.
  154. //
  155. TMenu::~TMenu()
  156. {
  157.   if (ShouldDelete && Handle)
  158.     ::DestroyMenu(Handle);
  159. }
  160.  
  161. //
  162. // Get the menu ID. If it's a regular menu item just returns its id.
  163. // If it's a popup menu, first attempt to retrieve a user-specified Id
  164. // via the MENUITEMINFO structure (32-bit only). Otherwise, use the Id of 
  165. // first menuitem minus 1.
  166. //
  167. uint
  168. TMenu::GetMenuItemID(int pos) const
  169. {
  170.   // Retrieve identifier
  171.   //
  172.   uint  id = ::GetMenuItemID(Handle, pos);
  173.   if (id != uint(-1)) {
  174.     TRACEX(OwlWin, 1, "GetMenuItemID at pos. " << pos << '=' <<  id);
  175.     return id;
  176.   }
  177.  
  178.  
  179.   // Try to retrieve a pop-up menu handle
  180.   //
  181.   HMENU popup = GetSubMenu(pos);
  182.   if (popup) {
  183.     TMenu subMenu(popup);
  184.  
  185.     // Here could try to retrieve the 'true' id of the popup if the user 
  186.     // provided one before proceeding with the 'Id of firt Item -1' OWL 
  187.     // enhancement. Need more information about MENUITEMINFO etc. 
  188.     // !!
  189.  
  190.     // Recurse within sub menu to retrieve popup Id.
  191.     //
  192.     id = subMenu.GetMenuItemID(0) - 1;
  193.     TRACEX(OwlWin, 1, "TMenu::GetMenuItemID - returns faked [Id of first "\
  194.                        "menu item - 1, id=" << dec << id);
  195.     return id;
  196.   }
  197.   TRACEX(OwlWin, 1, "TMenu::GetMenuItemID - unable to determine id - "\
  198.                      "returns 0");
  199.   return 0;
  200. }
  201.  
  202. #pragma warn -par  // resId param is never used in small model
  203. //
  204. //
  205. //
  206. void
  207. TMenu::CheckValid(uint resId)
  208. {
  209.   if (!Handle)
  210.     TXMenu::Raise(resId);
  211. }
  212. #pragma warn .par
  213.  
  214. //
  215. //
  216. //
  217. void
  218. TMenu::MeasureItem(MEASUREITEMSTRUCT far&)
  219. {
  220. }
  221.  
  222. //
  223. //
  224. //
  225. void
  226. TMenu::DrawItem(DRAWITEMSTRUCT far&)
  227. {
  228. }
  229.  
  230. //
  231. //
  232. //
  233. uint        
  234. TMenu::GetDefaultItem(bool getPos, uint flags) const
  235. {
  236.   PRECONDITION(Handle);
  237. #if defined(BI_PLAT_WIN16)
  238.   //
  239.   // For 16-bit applications, this API is only available when running
  240.   // under Win95. So we'll attempt to retrieve the proc. address from USER
  241.   //
  242.   typedef BOOL (WINAPI *FP)(HMENU, UINT, UINT);
  243.  
  244.   static FP fp = 0;
  245.   static bool getProc = false;
  246.   if (!getProc && !fp) {
  247.     fp = (FP)GetProcAddress(GetModuleHandle("USER"), "GetMenuDefaultItem");
  248.     getProc = true;
  249.   }
  250.   if (fp)
  251.     return fp(Handle, getPos ? TRUE : FALSE, flags) != FALSE;
  252.   return uint(-1);
  253.  
  254. #elif defined(BI_PLAT_WIN32)
  255.   return ::GetMenuDefaultItem(Handle, getPos ? TRUE : FALSE, flags);
  256. #endif 
  257. }
  258.  
  259. //
  260. //
  261. //
  262. bool        
  263. TMenu::SetDefaultItem(uint posOrId, bool isPos)
  264. {
  265.   PRECONDITION(Handle);
  266. #if defined(BI_PLAT_WIN16)
  267.   //
  268.   // For 16-bit applications, this API is only available when running
  269.   // under Win95. So we'll attempt to retrieve the proc. address from USER
  270.   //
  271.   typedef BOOL (WINAPI *FP)(HMENU, UINT, UINT);
  272.  
  273.   static FP fp = 0;
  274.   static bool getProc = false;
  275.   if (!getProc && !fp) {
  276.     fp = (FP)GetProcAddress(GetModuleHandle("USER"), "SetMenuDefaultItem");
  277.     getProc = true;
  278.   }
  279.   if (fp)
  280.     return fp(Handle, posOrId, isPos ? TRUE : FALSE) != FALSE;
  281.   return false;
  282.  
  283. #elif defined(BI_PLAT_WIN32)
  284.   PRECONDITION(Handle);
  285.   return ::SetMenuDefaultItem(Handle, posOrId, isPos ? TRUE : FALSE);
  286. #endif 
  287. }
  288.  
  289. //
  290. //
  291. //
  292. bool        
  293. TMenu::CheckRadioItem(uint first, uint last, uint check, uint flags)
  294. {
  295. #if   defined(BI_PLAT_WIN16)
  296.   // Emulate routine using pre-Win95 API
  297.   //
  298.   for (uint i = first; i <= last; i++)
  299.     CheckMenuItem(i, flags|(i == check ? MF_CHECKED : MF_UNCHECKED));
  300.   return true;
  301. #elif defined(BI_PLAT_WIN32)
  302.   PRECONDITION(Handle);
  303.   return ::CheckMenuRadioItem(Handle, first, last, check, flags) != FALSE;
  304. #endif 
  305. }
  306.  
  307. #if defined(BI_PLAT_WIN32)
  308. //
  309. //
  310. //
  311. bool        
  312. TMenu::GetMenuItemInfo(uint posOrId, bool isPos, TMenuItemInfo& mi) const
  313. {
  314.   PRECONDITION(Handle);
  315.   return ::GetMenuItemInfo(Handle, posOrId, isPos ? TRUE : FALSE, &mi) != FALSE;
  316. }
  317.  
  318. //
  319. //
  320. //
  321. bool        
  322. TMenu::SetMenuItemInfo(uint posOrId, bool isPos, TMenuItemInfo& mi)
  323. {
  324.   PRECONDITION(Handle);
  325.   return ::SetMenuItemInfo(Handle, posOrId, isPos ? TRUE : FALSE, &mi) != FALSE;
  326. }
  327.  
  328. //
  329. //
  330. //
  331. bool        
  332. TMenu::InsertMenuItem(uint posOrId, bool isPos, TMenuItemInfo& mi)
  333. {
  334.   PRECONDITION(Handle);
  335.   return ::InsertMenuItem(Handle, posOrId, isPos ? TRUE : FALSE, &mi) != FALSE;
  336. }
  337. #endif
  338.  
  339. //
  340. // Deep copy 'count' popup-menus or items from 'src' _appending_ to 'dst'
  341. // menu starting at 'offset' position in this menu
  342. //
  343. void
  344. TMenu::DeepCopy(TMenu& dst, const TMenu& src, int srcOff, int count)
  345. {
  346.   if (count < 0)
  347.     count = src.GetMenuItemCount() - srcOff;
  348.  
  349.   for (int i = 0; i < count; i++) {
  350.     uint  state = src.GetMenuState(srcOff+i, MF_BYPOSITION);
  351.     if (state == uint(-1))
  352.       return;
  353.  
  354.     char str[256];
  355.     TUser::GetMenuString(src, srcOff+i, str, sizeof(str), MF_BYPOSITION);
  356.  
  357.     // Currently does NOT support MF_BITMAP or MF_OWNERDRAW
  358.     //
  359.     if (state & MF_POPUP) {
  360.       state &= (MF_STRING | MF_POPUP);  // strip off breaks, separators, etc
  361.       TMenu subMenu(src.GetSubMenu(srcOff+i));
  362.       TMenu newSubMenu(NoAutoDelete);
  363.       DeepCopy(newSubMenu, subMenu);
  364.       dst.AppendMenu(state, newSubMenu, str);
  365.     }
  366.     else {
  367.       dst.AppendMenu(state, src.GetMenuItemID(srcOff+i), str);
  368.     }
  369.   }
  370. }
  371.  
  372. //
  373. // Deep copy 'count' popup-menus or items from 'src' to 'dst' menu
  374. // starting at 'srcOff' position in src and inserting at 'dstOff' in the
  375. // destination
  376. //
  377. void
  378. TMenu::DeepCopy(TMenu& dst, int dstOff, const TMenu& src, int srcOff, int count)
  379. {
  380.   if (count < 0)
  381.     count = src.GetMenuItemCount() - srcOff;
  382.  
  383.   for (int i = 0; i < count; i++) {
  384.     uint  state = src.GetMenuState(srcOff+i, MF_BYPOSITION);
  385.     if (state == uint(-1))
  386.       return;
  387.  
  388.     char   str[256];
  389.     src.GetMenuString(srcOff+i, str, sizeof(str), MF_BYPOSITION);
  390.  
  391.     // Currently does NOT support MF_BITMAP or MF_OWNERDRAW
  392.     //
  393.     if (state & MF_POPUP) {
  394.       state &= (MF_STRING | MF_POPUP);  // strip off breaks, separators, etc
  395.       TMenu subMenu(src.GetSubMenu(srcOff+i));
  396.       TMenu newSubMenu(NoAutoDelete);
  397.       DeepCopy(newSubMenu, subMenu);
  398.       if (dstOff >= 0)
  399.         dst.InsertMenu(dstOff, state|MF_BYPOSITION, newSubMenu, str);
  400.       else
  401.         dst.AppendMenu(state, newSubMenu, str);
  402.     }
  403.     else {
  404.       if (dstOff >= 0)
  405.         dst.InsertMenu(dstOff, state|MF_BYPOSITION, src.GetMenuItemID(srcOff+i), str);
  406.       else
  407.         dst.AppendMenu(state, src.GetMenuItemID(srcOff+i), str);
  408.     }
  409.   }
  410. }
  411.  
  412. //----------------------------------------------------------------------------
  413.  
  414. //
  415. // Create a system menu wrapper for the given window.
  416. //
  417. TSystemMenu::TSystemMenu(HWND hWnd, bool revert)
  418. :
  419.   TMenu(::GetSystemMenu(hWnd, revert), NoAutoDelete)
  420. {
  421. }
  422.  
  423. //----------------------------------------------------------------------------
  424.  
  425. //
  426. // Create an empty popup menu.
  427. //
  428. TPopupMenu::TPopupMenu(TAutoDelete autoDelete)
  429. :
  430.   TMenu(::CreatePopupMenu(), autoDelete)
  431. {
  432. }
  433.  
  434. //
  435. // Create a popup menu based on an existing popup menu.
  436. //
  437. TPopupMenu::TPopupMenu(HMENU handle, TAutoDelete autoDelete)
  438. :
  439.   TMenu(handle, autoDelete)
  440. {
  441. }
  442.  
  443. //
  444. // Create a popup menu from an existing menu.
  445. //
  446. TPopupMenu::TPopupMenu(const TMenu& menu, TAutoDelete autoDelete)
  447. :
  448.   TMenu(::CreatePopupMenu(), autoDelete)
  449. {
  450.   DeepCopy(*this, menu);
  451. }
  452.  
  453. //----------------------------------------------------------------------------
  454.  
  455. //
  456. // Create a TXMenu exception with the resID of the string resource.
  457. //
  458. TXMenu::TXMenu(uint resId)
  459. :
  460.   TXOwl(resId)
  461. {
  462. }
  463.  
  464.  
  465. //
  466. // Create a copy of the TXMenu exception.
  467. // It will be rethrown at a safer time.
  468. //
  469. #if defined(BI_NO_COVAR_RET)
  470. TXBase*
  471. #else
  472. TXMenu*
  473. #endif
  474. TXMenu::Clone()
  475. {
  476.   return new TXMenu(*this);
  477. }
  478.  
  479. //
  480. // Throw the exception.
  481. //
  482. void
  483. TXMenu::Throw()
  484. {
  485.   THROW( *this );
  486. }
  487.  
  488. //
  489. // Create a TXMenu exception and throw it.
  490. //
  491. void
  492. TXMenu::Raise(uint resId)
  493. {
  494.   TXMenu(resId).Throw();
  495. }
  496.